//
//  APBaseTableViewController.swift
//  APSwift
//
//  Created by jianbo.pei on 2023/3/29.
//

import Foundation
import UIKit

let defaultCellIdentifier = "defaultCellIdentifier"

class APBaseTableViewController: APBaseViewController {
    fileprivate lazy var internalTableView: UITableView = {
        let tableV = UITableView(frame: .zero, style: tableViewStyle())
        tableV.dataSource = self
        tableV.delegate = self
        if #available(iOS 15.0, *) {
            /// `iOS 15`中`UITableView`新增了一个属性：`sectionHeaderTopPadding`。此属性会给每一个`section header`增加一个默认高度，当我们使用`UITableViewStylePlain`初始化`UITableView`的时候，系统默认给`section header`增高了22像素。
            tableV.sectionHeaderTopPadding = 0
        }
        tableV.separatorStyle = .none
        tableV.separatorColor = nil
        return tableV
    }()
    
    private var internalTableViewVM: APTableView_VM_Protocol = VMBaseTableVM()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        registerCells()
        registerReuseViews()
    }
}

extension APBaseTableViewController {
    override func initUI() {
        super.initUI()
        view.addSubview(tableView)
    }
    
    override func makeConstraints() {
        super.makeConstraints()
        tableView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
    }
}

extension APBaseTableViewController: UITableViewDataSource, UITableViewDelegate {
    func numberOfSections(in tableView: UITableView) -> Int {
        return tableViewVM.sectionCount()
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tableViewVM.numberOfRows(in: section)
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let cellCls = tableViewVM.cellClass(at: indexPath) {
            if let cellCLS = cellCls.self as? any APReuseView_Identifier_Protocol.Type {
                let identifier = cellCLS.reuserIdentifier()
                let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
                if let cll = cell as? AP_V_Protocol {
                    let model = tableViewVM.model(at: indexPath)
                    cll.setup(model)
                }
                return cell
            } else {
                assert(false, k_vm_standardized_code + "❎❎❎error：\(NSStringFromClass(cellCls)) should conform to VMReuseView_Identifier_Protocol")
                 return defaultCell(for: tableView)
            }
        } else {
            return defaultCell(for: tableView)
        }
    }
    
    private func defaultCell(for tableView: UITableView) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: defaultCellIdentifier) {
            return cell
        } else {
            let cell = UITableViewCell.init(style: .default, reuseIdentifier: defaultCellIdentifier)
            return cell
        }
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if let cellCls = tableViewVM.cellClass(at: indexPath) {
            if let cellCLS = cellCls.self as? APView_Height_Protocol.Type {
                let model = tableViewVM.model(at: indexPath)
                return cellCLS.viewHeight(with: model)
            } else {
                assert(false, k_vm_standardized_code + "❎❎❎(error)：\(NSStringFromClass(cellCls)) should conform to VMView_Height_Protocol")
                return 0.0
            }
        } else {
            assert(false, k_vm_standardized_code + "❎❎❎error：tableViewVM should responds to `reuseViewClass(at`；or you can make sure tableViewVM is kind of VMBaseTableViewVM")
            return 0.0
        }
    }
    
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        if let cls = tableViewVM.reuseHeaderViewClass(in: section) {
            if let CLS = cls.self as? any APReuseView_Identifier_Protocol.Type {
                let identifier = CLS.reuserIdentifier()
                guard let reuseView = tableView.dequeueReusableHeaderFooterView(withIdentifier: identifier) else { return nil }
                if let v = reuseView as? AP_V_Protocol {
                    let model = tableViewVM.modelOfReuseHeaderView(in: section)
                    v.setup(model)
                }
                return reuseView
            } else {
                assert(false, k_vm_standardized_code + "❎❎❎error：\(NSStringFromClass(cls)) should conform to VMReuseView_Identifier_Protocol")
                 return nil
            }
        } else {
            return nil
        }
    }
    
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        if let cls = tableViewVM.reuseHeaderViewClass(in: section) {
            if let CLS = cls.self as? any APHeader_Height_Protocol.Type {
                let model = tableViewVM.modelOfReuseHeaderView(in: section)
                let height = CLS.headerViewHeight(with: model)
                return height
            } else {
                assert(false, k_vm_standardized_code + "❎❎❎error：\(NSStringFromClass(cls)) should conform to VMHeader_Height_Protocol")
                return 0.0
            }
        } else {
            return 0.0
        }
    }
    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        if let cls = tableViewVM.reuseFooterViewClass(in: section) {
            if let CLS = cls.self as? any APReuseView_Identifier_Protocol.Type {
                let identifier = CLS.reuserIdentifier()
                guard let reuseView = tableView.dequeueReusableHeaderFooterView(withIdentifier: identifier) else { return nil }
                if let v = reuseView as? AP_V_Protocol {
                    let model = tableViewVM.modelOfReuseFooterView(in: section)
                    v.setup(model)
                }
                return reuseView
            } else {
                assert(false, k_vm_standardized_code + "❎❎❎error：\(NSStringFromClass(cls)) should conform to VMReuseView_Identifier_Protocol")
                 return nil
            }
        } else {
            return nil
        }
    }
    
    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        if let cls = tableViewVM.reuseFooterViewClass(in: section) {
            if let CLS = cls.self as? any VMFooter_Height_Protocol.Type {
                let model = tableViewVM.modelOfReuseHeaderView(in: section)
                let height = CLS.footerViewHeight(with: model)
                return height
            } else {
                assert(false, k_vm_standardized_code + "❎❎❎error：\(NSStringFromClass(cls)) should conform to VMFooter_Height_Protocol")
                return 0.0
            }
        } else {
            return 0.0
        }
    }

}

extension APBaseTableViewController: APTableViewControllerProtocol {
    var tableViewVM: APTableView_VM_Protocol {
        get {
            internalTableViewVM
        }
        set {
            internalTableViewVM = newValue
        }
    }
    
    var tableView: UITableView {
        internalTableView
    }
    
    @objc func tableViewStyle() -> UITableView.Style {
        return .plain
    }
    
    @objc func tableViewRegisterCellClasses() -> [AnyClass] {
        guard let cls = tableViewVM.config.cellClass else { return [] }
        return [cls]
    }
    
    @objc func tableViewRegisterReuseViewClasses() -> [AnyClass] {
        var clses: [AnyClass] = []
        if let headerCls = tableViewVM.config.headerClass {
            clses.append(headerCls)
        }
        if let footerCls = tableViewVM.config.footerClass {
            clses.append(footerCls)
        }
        return clses
    }
    
    fileprivate func registerCells() {
        let cellClses = tableViewRegisterCellClasses()
        guard !cellClses.isEmpty else {
            return
        }
        for cellCls in cellClses {
            /// 参考链接：[Swift: check if generic type conforms to protocol](https://stackoverflow.com/questions/28124684/swift-check-if-generic-type-conforms-to-protocol)
            if let cellCLS = cellCls.self as? any APReuseView_Identifier_Protocol.Type {
                let identifier = cellCLS.reuserIdentifier()
                tableView.register(cellCls.self, forCellReuseIdentifier: identifier)
            }
        }
    }
    
    func registerReuseViews() {
        let reuseViewClses = tableViewRegisterReuseViewClasses()
        guard !reuseViewClses.isEmpty else {
            return
        }
        for reuseViewCls in reuseViewClses {
            if let reuseViewCLS = reuseViewCls.self as? any APReuseView_Identifier_Protocol.Type {
                let identifier = reuseViewCLS.reuserIdentifier()
                tableView.register(reuseViewCls.self, forHeaderFooterViewReuseIdentifier: identifier)
            }
        }
    }
    
    func pullRefresh() {
        
    }
    
    func loadMore() {
        
    }
    
}
